<template>
  <el-drawer
    class="basic-drawer detail-view"
    :model-value="visible"
    :loading="loading"
    :title="title"
    :size="800"
    :close-on-click-modal="true"
    :close-on-press-escape="true"
    @opened="handleOpen"
    @closed="handleClose"
  >
    <el-form
      ref="formRef"
      v-loading="detailLoading"
      :model="formState"
      :rules="rules"
      require-asterisk-position="right"
      label-position="top"
      @submit.prevent
    >
      <el-form-item label="主域名" prop="primary_domain">
        <el-input
          v-model.trim="formState.primary_domain"
          maxlength="100"
          placeholder="请输入域名"
        />
      </el-form-item>
      <el-form-item label="其他域名" prop="other_domain">
        <el-input
          v-model="formState.other_domain"
          type="textarea"
          :rows="5"
          placeholder="请输入域名，一行一个，最多10个"
        />
      </el-form-item>
      <el-form-item label="备注" class="hide-star" prop="description">
        <el-input
          v-model.trim="formState.description"
          maxlength="20"
          placeholder="请输入备注"
        />
      </el-form-item>
      <el-form-item prop="acme_account_id" label="Acme 账户">
        <el-select
          v-model="formState.acme_account_id"
          v-loadmore="loadMore"
          :teleported="false"
          class="w-full"
        >
          <template #label="{ value, label }">
            <section class="flex items-center">
              <span>{{ label }} </span>
              <div
                class="px-2 bg-[#E8F3FF] text-[#165DFF] text-xs/5 rounded ml-[6px]"
              >
                {{
                  getOptionsLabel(
                    ACCOUNT_TYPE_OPTS,
                    acmeOpts.find(item => item.value === value)?.type
                  )
                }}
              </div>
            </section>
          </template>
          <el-option
            v-for="item in acmeOpts"
            :key="item.label"
            :label="item.label"
            :value="item.value"
            >{{ item.label }}
            <div
              class="px-2 bg-[#E8F3FF] text-[#165DFF] text-xs/5 rounded ml-[6px]"
            >
              {{ item.content }}
            </div>
          </el-option>
        </el-select>
      </el-form-item>
      <el-form-item prop="key_type" label="加密算法">
        <el-select
          v-model="formState.key_type"
          class="w-full"
          :disabled="!!record?.id"
        >
          <el-option
            v-for="item in ALGORITHM_OPTS"
            :key="item.label"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
      </el-form-item>
      <el-form-item prop="provider" label="验证方式">
        <el-radio-group v-model="formState.provider" @change="handleDnsChange">
          <el-radio value="dns_account" label="dns_account">DNS账号</el-radio>
          <el-radio value="dns_manual" label="dns_manual">手动解析</el-radio>
        </el-radio-group>
      </el-form-item>
      <el-form-item
        v-if="formState.provider === 'dns_account'"
        prop="dns_account_id"
        label="DNS账号"
      >
        <el-select
          v-model="formState.dns_account_id"
          v-loadmore="dnsLoadMore"
          :teleported="false"
          class="w-full"
        >
          <template #label="{ value, label }">
            <section class="flex items-center">
              <span>{{ label }} </span>
              <div
                class="px-2 bg-[#E8F3FF] text-[#165DFF] text-xs/5 rounded ml-[6px]"
              >
                {{
                  getOptionsLabel(
                    PROVIDER_TYPE,
                    dnsOpts.find(item => item.value === value)?.type!
                  )
                }}
              </div>
            </section>
          </template>
          <el-option
            v-for="item in dnsOpts"
            :key="item.label"
            :label="item.label"
            :value="item.value"
            >{{ item.label }}
            <div
              class="px-2 bg-[#E8F3FF] text-[#165DFF] text-xs/5 rounded ml-[6px]"
            >
              {{ item.content }}
            </div>
          </el-option>
        </el-select>
      </el-form-item>
      <el-form-item
        v-if="formState.provider === 'dns_account'"
        prop="auto_renew"
        label=""
      >
        <el-checkbox
          v-model="formState.auto_renew"
          @change="handleProviderChange"
          >自动续签</el-checkbox
        >
      </el-form-item>
      <el-form-item label="DNS服务器1" class="hide-star" prop="server1">
        <el-input
          v-model.trim="formState.server1"
          maxlength="20"
          placeholder="使用自定义的 DNS 服务器来校验域名"
        />
      </el-form-item>
      <el-form-item label="DNS服务器2" class="hide-star" prop="server2">
        <el-input
          v-model.trim="formState.server2"
          maxlength="20"
          placeholder="使用自定义的 DNS 服务器来校验域名"
        />
      </el-form-item>
    </el-form>
    <template #footer>
      <section class="flex justify-end">
        <el-button @click="emit('update:visible', false)">返回</el-button>
        <el-button type="primary" :loading="loading" @click="handleSubmit"
          >确认</el-button
        >
      </section>
    </template>
  </el-drawer>
  <log-dialog
    v-model:visible="logState.visible"
    :record="logState.record"
    @refresh-row="row => emit('refresh-row', row)"
  />
</template>
<script lang="ts" setup>
import type { FormInstance, FormItemRule } from 'element-plus'

import type {
  CertCreateModel,
  CertModel,
  CertUpdateModel
} from '@/apis/model/cert'
import { ACCOUNT_TYPE_OPTS, ALGORITHM_OPTS } from '@/config/constant/cert'
import { PROVIDER_TYPE } from '@/config/constant/dns'

import LogDialog from '../dialogs/LogDialog.vue'
interface IProps {
  visible: boolean
  record?: CertModel
  loading?: boolean
}
const props = withDefaults(defineProps<IProps>(), {
  visible: false,
  loading: false
})
// 刷新表格事件
interface IEmit {
  (event: 'update:visible', value: boolean): void
  (event: 'update:loading', value: boolean): void
  (event: 'refresh'): void
  (event: 'refresh-row', value: CertModel): void
}
const emit = defineEmits<IEmit>()
const title = computed(() => (props.record?.id ? '编辑证书' : '申请证书'))
const formRef = ref<FormInstance>()

interface IFormState extends CertUpdateModel, CertCreateModel {
  other_domain: string
  server1: string
  server2: string
}
const formState = ref<IFormState>({
  id: '',
  primary_domain: '',
  domain_list: [],
  other_domain: '',
  description: '',
  acme_account_id: '',
  dns_account_id: '',
  provider: 'dns_account',
  auto_renew: true,
  server1: '',
  server2: '',
  nameserver_list: [],
  key_type: 'P256'
})
const validateDomain = (_rule: any, value: any, callback: any) => {
  if (!value) return callback()
  const valueList = value.split('\n').filter(Boolean)
  const num = valueList.length
  let isOut
  valueList.map((item: string) => {
    item = item.trim()
    if (item.length > 100) {
      return new Error('域名总长度不能超过100个字符')
    }
    if (item.startsWith('*.')) {
      item = item.substring(2, item.length - 1)
    }
    if (!wildcardDomainReg.test(item)) isOut = true
  })
  if (isOut) {
    callback(new Error('域名格式不正确'))
  } else if (num > 10) {
    callback(new Error('已超过配置上限，请核对'))
  } else {
    callback()
  }
}
const rules: Record<string, FormItemRule[]> = {
  primary_domain: [
    { required: true, message: '请输入域名', trigger: 'blur' },
    {
      trigger: 'blur',
      validator(_, value, callback: any) {
        let isOut
        if (value.length > 255) {
          return new Error('域名总长度不能超过255个字符')
        }
        if (value.startsWith('*.')) {
          value = value.substring(2, value.length - 1)
        }
        if (domainReg.test(value) || ipv4Reg.test(value)) {
          isOut = false
        } else {
          isOut = true
        }
        if (isOut) {
          callback(new Error('域名格式不正确'))
        } else {
          callback()
        }
      }
    }
  ],
  other_domain: [
    { required: false, message: '请输入域名', trigger: 'blur' },
    {
      validator: validateDomain
    }
  ],
  dns_account_id: [{ required: true, message: '请选择', trigger: 'change' }],
  acme_account_id: [{ required: true, message: '请选择', trigger: 'change' }],
  key_type: [{ required: true, message: '请选择', trigger: 'change' }],
  provider: [{ required: true, message: '请选择', trigger: 'change' }]
}
const logState = reactive({
  visible: false,
  record: { id: '', title: '' },
  loading: false
})
// const messageDetail = ref<NoticeListReturn>()

const acmeOpts = ref<{ label: string; value: string; content: string }[]>([])
const pageData = reactive({
  offset: 0,
  limit: 10
})
const handleProviderChange = (val: boolean) => {
  if (val === 'dns_manual') formState.value.auto_renew = false
}
const getAcmeOpts = () => {
  getAcmeApi({
    order: 'asc',
    sort: 'created_at',
    ...pageData
  }).then((res: any) => {
    if (res.list.length < 1) {
      ToastUtils.warning('没有更多数据了...')
    }
    const newOptions = res.list.map((item: any) => {
      return {
        value: item.id,
        label: item.email,
        type: item.type,
        content: getOptionsLabel(ACCOUNT_TYPE_OPTS, item.type)
      }
    })
    acmeOpts.value.push(...newOptions)
  })
}

// 触底了，继续发请求
const loadMore = async () => {
  pageData.offset = pageData.offset + 1
  await getAcmeOpts()
}
const dnsOpts = ref<{ label: string; value: string; content: string }[]>([])
const dnsPageData = reactive({
  offset: 0,
  limit: 10
})
const getDnsOpts = () => {
  getDnsApi({
    order: 'asc',
    sort: 'created_at',
    ...dnsPageData
  }).then((res: any) => {
    if (res.list.length < 1) {
      ToastUtils.warning('没有更多数据了...')
    }
    const newOptions = res.list.map((item: any) => {
      return {
        value: item.id,
        label: item.name,
        type: item.type,
        content: getOptionsLabel(PROVIDER_TYPE, item.type)
      }
    })
    dnsOpts.value.push(...newOptions)
  })
}
const dnsLoadMore = async () => {
  dnsPageData.offset = dnsPageData.offset + 1
  await getDnsOpts()
}
const handleDnsChange = (val: string) => {
  if (val === 'dns_account') {
    nextTick(() => {
      formState.value.dns_account_id =
        (!!Number(props.record?.dns_account_id) &&
          props.record?.dns_account_id) ||
        dnsOpts.value[0].value
    })
  }
}
watchEffect(() => {
  if (!props.record?.id) {
    if (acmeOpts.value.length) {
      formState.value.acme_account_id = acmeOpts.value[0].value
    }
    if (dnsOpts.value.length) {
      formState.value.dns_account_id = dnsOpts.value[0].value
    }
  }
})
const detailLoading = ref(false)
const getDetail = (id: string) => {
  detailLoading.value = true
  getCertApi({ id })
    .then((res: any) => {
      Object.assign(formState.value, res)
      formState.value.other_domain = formState.value.domain_list?.length!
        ? formState.value.domain_list.join('\n')
        : ''
      formState.value.server1 = res?.nameserver_list?.[0] || ''
      formState.value.server2 = res?.nameserver_list?.[1] || ''
    })
    .finally(() => {
      detailLoading.value = false
    })
}
//弹窗打开
const handleOpen = () => {
  getAcmeOpts()
  getDnsOpts()
  if (props?.record?.id) {
    getDetail(props?.record?.id)
  } else {
    formState.value.other_domain = ''
    formState.value.server1 = ''
    formState.value.server2 = ''
  }
}

async function handleSubmit() {
  await formRef.value?.validate()
  const params = { ...formState.value }
  const record = props.record
  const apiPath = record?.id ? updateCertApi : createCertApi
  params.domain_list = params.other_domain.split('\n').filter(Boolean) || []
  params.nameserver_list = [params.server1, params.server2].filter(Boolean)
  if (params.provider === 'dns_manual') params.dns_account_id = '0'
  emit('update:loading', true)
  apiPath({ ...params } as any)
    .then((res: any) => {
      emit('update:loading', false)
      if (record?.id) ToastUtils.success('修改成功，下次申请时生效')
      handleClose()
      emit('refresh')
      if (params?.provider === 'dns_account' && !record?.id) {
        logState.visible = true
        logState.record = { id: res?.id, title: params.primary_domain }
      }
    })
    .finally(() => emit('update:loading', false))
}
//弹窗关闭
const handleClose = () => {
  acmeOpts.value = []
  dnsOpts.value = []
  formState.value.domain_list = []
  formRef.value?.resetFields()
  emit('update:visible', false)
}
</script>

<style lang="scss" scoped>
.detail-view {
  .detail-title {
    border-bottom: 1px solid #edeef0;
    @apply pb-4;
  }

  .detail-body {
    @apply pt-4 leading-[22px];
    align-self: stretch;
  }
}
</style>
